%{
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <string.h>
#include <math.h>
#include <sys/time.h>
#include "config.h"
#include <vector>

using namespace std;
/*
struct qplan {
	table *outer;
	table *inner;
	int 	flag;
};
*/
	
class attrib_field {
public:
	char tablename[TABLE_NAME_LENGTH];
	char attribname[ATTRIB_NAME_LENGTH];
	int offset;
	int value;
	int agg_type;

	attrib_field()
	{
		tablename[TABLE_NAME_LENGTH-1] = '\0';
		attribname[ATTRIB_NAME_LENGTH-1] = '\0';
		offset=-1;
		value=0;
		agg_type = ISNULL_TYPE;
	}

	void print()
	{
		if(agg_type != ISNULL_TYPE)
		{
			if(agg_type == SUM)	
			{
				PRINT(" %4s", "SUM(");
				PRINT("%s",attribname);
				PRINT(")");
			}
			else if(agg_type == AVG)	
			{
				PRINT(" %4s", "AVG(");
				PRINT("%s",attribname);
				PRINT(")");
			}
			else if(agg_type == MAX)	
			{
				PRINT(" %4s", "MAX(");
				PRINT("%s",attribname);
				PRINT(")");
			}
			else if(agg_type == MIN)	
			{
				PRINT(" %4s", "MIN(");
				PRINT("%s",attribname);
				PRINT(")");
			}
			else if(agg_type == COUNT)	
			{
				PRINT(" %4s", "CNT(");
				PRINT("%s",attribname);
				PRINT(")");
			}
			else
			{
				PRINT(" %4s",attribname);
			}
		}
		else
		{
			PRINT(" %8s",attribname);
		}

#ifdef DEBUG
		cout<<"tname="<<tablename<<", attrib="<<attribname<<", value="<<value<<",offset= "<<offset<<",agg_type="<<agg_type<<endl;
#endif
	}

	void printvalue(int count)
	{
		switch(agg_type) {
			case SUM:
			case MIN:
			case MAX:
			case COUNT:
			case ISNULL_TYPE:
				PRINT("%8d ", value);
				break;
			case AVG:
				PRINT("%8.2f ",(float) value/count);
				break;
			default:
				FATAL("Print call with invalid AGG-TYPE\n");
		}
	}
};



class condition {
public:
	int isfield1;	//0-value 1-attrib 2-tattrib 3-condition
	int isfield2;
	void *f1;
	int op;
	void *f2;

	char * get_table_name()
	{
		if(isfield1 == ISTATTRIB_TYPE)
			return ((attrib_field *)f1)->tablename;
	}

	void print()
	{
		cout<<endl<<"<con>"<<endl;
		cout << "F1: " << isfield1;
		if(isfield1!=ISCONDITION_TYPE)
		{
			((attrib_field*)f1)->print();
		}
		else
		{
			((condition*)f1)->print();
		}

		cout<<"OP: "<<op<<endl;

		cout << "F2: " << isfield2;
		if(isfield2!=ISCONDITION_TYPE)
		{
			((attrib_field*)f2)->print();
		}
		else
		{
			((condition*)f2)->print();
		}

		cout<<endl<<"<\\con>"<<endl;
	}
};

void print_attriblist(vector<attrib_field*> v);
void print_attriblist_values(vector<attrib_field*> attlist);
void print_attriblist_values(vector<attrib_field*> attlist, int count);

#include "index.hh"
#include "stg_mgr.hh"
#include "block.hh"
#include "buf_mgr.hh"
#include "table.hh"
#include "db.hh"

#define yywrap()	0

class catalog *db1;

FlexLexer* lexer;
char tokens[MAX_TOKENS][MAX_TOKEN_SIZE];
int token_num = 0;
int status = 0;
int invalid_data = 0;
int num_blocks = 0;

double	command_time = 0;
clock_t start, finish;
int	timer=0;
struct timeval t_start, t_finish;
struct timezone tz1;

#include "query_processor.hh"

int main(int argc, char *argv[])
{
	START;
	getversion();
	++argv, --argc;  /* Skip over program name. */

	lexer = new yyFlexLexer;

	if (argc > 0)
		
		num_blocks = atoi(argv[0]);
	else
		num_blocks = NUM_BLOCKS;
	
	db1 = new catalog(CATALOG_FILE, num_blocks);
	END;

	while(lexer->yylex() != 0);

	return 0;
}



%}

DIGIT		[0-9]
ALPHA		[a-zA-Z]
ALPHANUM	[a-zA-Z0-9]
OP		=|>|<
AGG		(SUM)|(AVG)|(MAX)|(MIN)|(COUNT)



NAME		{ALPHA}{ALPHANUM}{0,16}
TABLE_NAME	{ALPHA}{ALPHANUM}{0,7}
ATTRIB_NAME	{ALPHA}{ALPHANUM}{0,2}
TATTRIB		{TABLE_NAME}.{ATTRIB_NAME}
NUMBER		({DIGIT}{0,31})|([-]{DIGIT}{0,31})
AGGATTRIB	{AGG}[(]{ATTRIB_NAME}[)]
AGGTATTRIB	{AGG}[(]{TATTRIB}[)]

TABLE_NAME2	[,]{ALPHA}{ALPHANUM}{0,2}
ATTRIB_NAME2	[,]{ALPHA}{ALPHANUM}{0,2}
TATTRIB2	[,]{TABLE_NAME}.{ATTRIB_NAME}
NUMBER2		[,]{DIGIT}{0,31}
AGGATTRIB2	[,]{AGG}[(]{ATTRIB_NAME}[)]
AGGTATTRIB2	[,]{AGG}[(]{TATTRIB}[)]

TABLE_NAMES	{TABLE_NAME}{TABLE_NAME2}{0,100}
ATTRIB_NAMES	{ATTRIB_NAME}{ATTRIB_NAME2}{0,7}
TATTRIBS	{TATTRIB}{TATTRIB2}{0,15}
NUMBERS		({NUMBER}{NUMBER2}{0,7})
AGGATTRIBS	{AGGATTRIB}{AGGATTRIB2}{0,7}
AGGTATTRIBS	{AGGTATTRIB}{AGGTATTRIB2}{0,7}

SL_ATTRIBS	([*])|({ATTRIB_NAMES})|({AGGATTRIBS})
JSL_ATTRIBS	([*])|({TATTRIBS})|({AGGTATTRIBS})
NODUPS		[[]NO[ ]DUPLICATES[]]

%%
CREATE[ ]TABLE[ ]{TABLE_NAME}[(]{ATTRIB_NAMES}[)];[\n]		{ START; create_table(); END; }
INSERT[ ]INTO[ ]{TABLE_NAME}[ ]VALUES[(]{NUMBERS}[)];[\n]	{ START; insert_values(); END; }

SELECT[ ]COUNT[(][*][)][ ]FROM[ ]{TABLE_NAME};[\n]						{ START; select_join_call();      END; }
SELECT[ ]{SL_ATTRIBS}[ ]FROM[ ]{TABLE_NAME};[\n]						{ START; select_join_call();      END; }
SELECT[ ]COUNT[(][*][)][ ]FROM[ ]{TABLE_NAME}[ ]WHERE[ ]{ATTRIB_NAME}{OP}{NUMBER};[\n]		{ START; select_join_call();      END; }
SELECT[ ]{SL_ATTRIBS}[ ]FROM[ ]{TABLE_NAME}[ ]WHERE[ ]{ATTRIB_NAME}{OP}{NUMBER};[\n]		{ START; select_join_call();      END; }

SELECT[ ]COUNT[(][*][)][ ]FROM[ ]{TABLE_NAMES};[\n]				{ START; select_join_call(); END; }
SELECT[ ]{JSL_ATTRIBS}[ ]FROM[ ]{TABLE_NAMES};[\n]				{ START; select_join_call(); END; }
SELECT[ ]COUNT[(][*][)][ ]FROM[ ]{TABLE_NAMES}[ ]WHERE[ ]{TATTRIB}{OP}{NUMBER};[\n]	{ START; select_join_call(); END; }
SELECT[ ]{JSL_ATTRIBS}[ ]FROM[ ]{TABLE_NAMES}[ ]WHERE[ ]{TATTRIB}{OP}{NUMBER};[\n]	{ START; select_join_call(); END; }

SELECT[ ]COUNT[(][*][)][ ]FROM[ ]{TABLE_NAMES}[ ]WHERE[ ]{TATTRIB}={TATTRIB};[\n]				{ START; select_join_call(); END; }
SELECT[ ]{JSL_ATTRIBS}[ ]FROM[ ]{TABLE_NAMES}[ ]WHERE[ ]{TATTRIB}={TATTRIB};[\n]				{ START; select_join_call(); END; }
SELECT[ ]COUNT[(][*][)][ ]FROM[ ]{TABLE_NAMES}[ ]WHERE[ ]{TATTRIB}={TATTRIB}[ ]AND[ ]{TATTRIB}{OP}{NUMBER};[\n]	{ START; select_join_call(); END; }
SELECT[ ]{JSL_ATTRIBS}[ ]FROM[ ]{TABLE_NAMES}[ ]WHERE[ ]{TATTRIB}={TATTRIB}[ ]AND[ ]{TATTRIB}{OP}{NUMBER};[\n]	{ START; select_join_call(); END; }

PRINT[ ]TABLE[ ]{TABLE_NAME};[\n]	{ START; print_table();   END; }
PRINT[ ]CATALOG;[\n]			{ START; print_catalog(); END; }

PRINT[ ]HIT[ ]RATE;[\n]			{ START; print_hit_rate(); END;	}
PRINT[ ]BUFFER[ ]{DIGIT};[\n]		{ START; print_buffer();  END;	}
PRINT[ ]BUFFER;[\n]			{ START; print_buffers(); END;	}

SET[ ]TIMER[ ]ON;[\n]			{ START; timer=1; PRINT("Timer is now ON \n"); END; }
SET[ ]TIMER[ ]OFF;[\n]			{ START; timer=0; PRINT("Timer is now OFF\n"); END; }

SET[ ]INDEX[ ]DEBUG[ ]ON;[\n]		{ START; iDebugON=1;PRINT("INDEX DEBUG Mode is now ON\n");  END;	}
SET[ ]INDEX[ ]DEBUG[ ]OFF;[\n]		{ START; iDebugON=0;PRINT("INDEX DEBUG Mode is now OFF\n"); END;	}

SET[ ]JOIN[ ]DEBUG[ ]ON;[\n]		{ START; jDebugON=1;PRINT("JOIN DEBUG Mode is now ON\n");  END;	}
SET[ ]JOIN[ ]DEBUG[ ]OFF;[\n]		{ START; jDebugON=0;PRINT("JOIN DEBUG Mode is now OFF\n"); END;	}

SET[ ]FILE[ ]DEBUG[ ]ON;[\n]		{ START; fDebugON=1;PRINT("FILE I/O DEBUG Mode is now ON\n");  END;	}
SET[ ]FILE[ ]DEBUG[ ]OFF;[\n]		{ START; fDebugON=0;PRINT("FILE I/O DEBUG Mode is now OFF\n"); END;	}

CREATE[ ]INDEX[ ]{NAME}[ ]ON[ ]{TABLE_NAME}[(]{ATTRIB_NAME}[)];[\n] 		{ START; create_index(1); END;	}
CREATE[ ]INDEX[ ]{NAME}[ ]ON[ ]{TABLE_NAME}[(]{ATTRIB_NAME}[)][ ]{NODUPS};[\n]	{ START; create_index(0); END;	}

PRINT[ ]INDEX[ ]{NAME};[\n]		{ START; print_index(); END; }

COMMIT[;][\n]				{ START; commit(); 	END; }
QUIT[;][\n]				{ quit(); exit(status);	     } 

[\n]					{ if(invalid_data) PRINT("Invalid Query\n"); invalid_data=0; END; }
.					{ invalid_data=1;			}
%%

